﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using UtilZ.Dotnet.Ex.ZLog;

namespace UtilZ.Dotnet.Ex.Communication.Net.Ftp
{
    /// <summary>
    /// 指定服务器要连接的地址和端口
    /// Specifies an address and port to which the server should connect.
    /// </summary>
    internal class FtpPORTCommand : FtpCommandAbs
    {
        /***********************************************************************************************************
        * [PORT]（Data  Port，数据端口）命令
        * 说明：为数据连接指定一个IP地址和本地端口。
        * 
        * 用法：PORT<Socket><CRLF>
        * 参数：Socket是数据连接中要使用的数据端口的一个HOST-PORT规约。用户和服务器都有默认的数据端口，在正常情况下不需要这条命令和对 它的应答。如果使用了这条命令，则参数是一个32个Internet主机地址和一个16位TCP端口地的拼接。这个地址信息被拆分为8位的字段，并且每个 字段的值是作为一个十制数传输的（在字符串意义上）。各个字段用逗号分隔开。一条端口命令可以是这样：
        * PORT h1,h2,h3,p1,p2
        * 其中H1是Internet主机地址的高位字节，P1是本地端口的高位字节。
        * 例子：
        * SendData "PORT 199,199,199,0,33,1" + “/r/n
        * 
        * 返回值如下（粗体表示成功）：
        * 200  命令成功。
        * 421  服务不可用，关闭控制连接。
        * 
        * 如果某项服务获知自己即将关闭，会向所有命令做出这个应答。
        * 500  语法错误，无法识别命令。
        * 
        * 这其中包括命令行过长之类的错误。
        * 501  参数或变元中有语法错误。
        * 530  无法登录。
        * 
        ************************************************************************************************************/


        public FtpPORTCommand()
            : base()
        {

        }


        protected override string[] GetNames()
        {
            return new string[] { FtpCommands.PORT };
        }

        protected override IFtpResponse PrimitiveExcute(FtpSession session, string command, string commandLine)
        {
            //Request: PORT 192,168,10,103,211,216 # PORT，这里用于指定客户端的IP地址和端口
            //Response: 200 PORT command successful. Consider using PASV. # 表示命令执行成功， 这里是端口连接成功

            try
            {
                switch (session.FtpServer.Config.WorkMode)
                {
                    case FtpWorkMode.Port:
                    case FtpWorkMode.Mix:
                        break;
                    default:
                        return new FtpCodeResponse(FtpStatusCodes.Code502, "Command not excute.");
                }

                string[] strs = commandLine.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
                if (strs.Length != 6)
                {
                    return new FtpCodeResponse(FtpStatusCodes.Code501, "Invalid parameter");
                }

                string ipStr = string.Join(".", strs, 0, 4);
                var ipAddr = IPAddress.Parse(ipStr);
                int port = int.Parse(strs[4]) * 256 + int.Parse(strs[5]);
                var dataTranfer = new FtpPortDataTranfer(session, new IPEndPoint(ipAddr, port));
                session.SetDataTranferObject(dataTranfer);
                return dataTranfer.GetFtpResponse();
            }
            catch (Exception ex)
            {
                return new FtpCodeResponse(FtpStatusCodes.Code451, ex.Message);
            }
        }
    }

}
